package handler

import (
	"strconv"
	"time"
	"web_framework/config"
	"web_framework/model"
	"web_framework/pkg/constvar"
	"web_framework/service"
	"web_framework/storage"
	"web_framework/pkg/e"
)

//保持心跳
type RouterHeartHandle struct {
}

var errInfo string
func (routerHeartHandle RouterHeartHandle) handleMsg(data model.Request, sn string) (result model.Response) {
	e.Log("Info", "心跳请求正常")
	//检查参数是否为空
	if len(sn) == 0 {
		e.Log("Info", "sn参数必传")
		return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "sn参数必传")
	}
	//更新上下行速度
	speedCacheKey := constvar.RouterRedisPrefix + sn + storage.RedisRouterActualSpeedKey
	hashData := map[string]interface{}{
		"upspeed":   e.SpeedUnitConversion(data.Data.UpSpeed),
		"downspeed": e.SpeedUnitConversion(data.Data.DownSpeed),
	}

	storage.RedisHSet(speedCacheKey, hashData, -1)
	//查询下载中的任务队列
	loadingTasks, getTaskListErr := service.GetLoadingTask(sn)
	if getTaskListErr != nil {
		e.Log("Info", "获取下载中任务队列失败")
		return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "获取下载中任务队列失败")
	}
	//更新任务状态
	for _, task := range data.Data.Tasks {
		taskIdStr := strconv.FormatInt(task.TaskID,10)
		_, ok := loadingTasks[taskIdStr]
		if ok != true{
			continue
		}
		if task.Status == model.DownLoadTaskComplete {
			taskIdInt64, _ := strconv.ParseInt(taskIdStr, 10, 64)
			timeNow := time.Now()
			//更新数据库任务状态
			newTaskInfo := model.Task{
				TotalSize:    task.TotalSize,
				Path:         task.Path,
				Status:       model.TaskStatusComplete,
				CompleteTime: &timeNow,
			}
			if _, err := storage.UpdateTaskInfo(config.C.DB.DB, task.TaskID, newTaskInfo); err != nil {
				return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "修改数据库任务状态失败"+err.Error())
			}
			//更新任务队列信息
			if err := service.DelLoadTask(taskIdInt64, sn, model.TaskStatusComplete); err != nil {
				e.Log("Info", "任务完成，更新任务队列失败")
			}

			//任务通知
			tokenSilce,getTokenErr := service.GetUserTokenBySn(sn)
			if getTokenErr != nil {
				e.Log("Info", "更新任务队列失败", getTokenErr.Error())
				return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, getTokenErr.Error()+",更新任务队列失败")
			}

			mid,_ := service.GenMid(sn)
			var requestData = model.Request{
				Mid:    mid,
				Mtype:constvar.MTypeTaskDealNoticeRequest,
				Data:	&model.RequestData{
					TaskID: data.Data.TaskID,
					Notice: data.Data.Notice,
				},
			}
			//获取推送的消息体
			for _,clientToken := range tokenSilce{
				conn,ok:=RouterMaps[clientToken]
				if ok {
					Route(requestData,conn)
				}
			}
			//重新推送下载队列
			requestMsg,_ := routerHeartHandle.getPushData(sn)
			client := []string{sn}
			WriteMessage(client,requestMsg)
		} else {
			taskStatus := model.TaskStatusloading
			//任务暂停
			if task.Status == model.DownLoadTaskPause{
				taskStatus = model.TaskStatusPaused
			}else if task.Status == model.DownLoadTaskLoadFail{   //任务下载失败
				taskStatus = model.TaskStatusLoadFail
				//从下载队列中移除
				if err := service.DelTaskFromLoadingQueue(task.TaskID, sn); err != nil {
					e.Log("Info", "任务下载失败，任务从下载队列中移除失败")
				}
			}
			cacheKey := constvar.RouterRedisPrefix + sn + storage.RedisRouterTaskInfoKey + ":" + taskIdStr
			cacheData := map[string]interface{}{
				"speed":          task.Speed,
				"totalSize":      task.TotalSize,
				"downloadedSize": task.DownloadSize,
				"path":           task.Path,
				"status":   taskStatus,
			}
			_, setErr := storage.RedisHSet(cacheKey, cacheData, -1)
			if setErr != nil {
				e.Log("Info", "任务信息更新失败")
				return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "任务信息更新失败")
			}
			//重新推送下载队列
			requestMsg,_ := routerHeartHandle.getPushData(sn)
			client := []string{sn}
			WriteMessage(client,requestMsg)
		}

	}

	//更新设备信息
	//var devicesMap = make(map[string]model.Device)
	if data.Data.Devices != nil{
		onlineDeivceList ,_ := service.GetOnlineDeviceList(sn)
		offlineDeviceList ,_ := service.GetOfflineDeviceList(sn)
		nowTimeUnix := time.Now().Unix()
		for _,device := range data.Data.Devices{
			_,ok := onlineDeivceList[device.Mac]
			//已经接入
			if ok{
				delete(onlineDeivceList, device.Mac)
				deviceUUID := e.Md5Str(sn+device.Mac)
				deviceInfoCacheKey := constvar.RouterRedisPrefix + sn + storage.RedisJoinDeviceInfoKey + ":" + deviceUUID
				cacheData := map[string]interface{}{
					"dspeed":e.SpeedUnitConversion(device.Dspeed),
					"upspeed":e.SpeedUnitConversion(device.Upspeed),
					"status":storage.JoinDevicesOnline,
				}
				_, setErr := storage.RedisHSet(deviceInfoCacheKey, cacheData, -1)
				if setErr != nil {
					e.Log("Info", "设备信息更新失败")
					return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "设备信息更新失败")
				}
			}else{  //最新接入

				deviceUUID := e.Md5Str(sn+device.Mac)
				deviceInfoCacheKey := constvar.RouterRedisPrefix + sn + storage.RedisJoinDeviceInfoKey + ":" + deviceUUID
				//截取mac后8位，查询数据库获取设备类型
				macAfter8byte := device.Mac[9 : len(device.Mac)]
				mobileType,getMoleTypeErr :=storage.GetDeviceType(config.C.DB.DB , macAfter8byte)
				if getMoleTypeErr != nil{
					//return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "根据mac查询设备类型失败")
				}
				var deviceType int
				if mobileType.Remark == "apple"{
					deviceType = 1
				}else if mobileType.Remark == "其它"{
					deviceType = 3
				}else{
					deviceType = 2
				}
				cacheData := map[string]interface{}{
					"mac":device.Mac,
					"name": "huawei",  //TODO
					"join":e.TimeToStr(nowTimeUnix),
					"dspeed":e.SpeedUnitConversion(device.Dspeed),
					"upspeed":e.SpeedUnitConversion(device.Upspeed),
					"type":deviceType,
					"status":storage.JoinDevicesOnline,
					"ip":device.IP,
				}
				_, setErr := storage.RedisHSet(deviceInfoCacheKey, cacheData, -1)
				if setErr != nil {
					e.Log("Info", "设备信息更新失败")
					return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "设备信息更新失败")
				}

				OnlineJoinDeviceListCacheKey := constvar.RouterRedisPrefix + sn + storage.RedisJoinDeviceOnlineListKey
				_, err := storage.RedisZAdd(OnlineJoinDeviceListCacheKey, device.Mac, nowTimeUnix)
				if err != nil {
					e.Log("Info", "添加在线设备失败")
					return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "添加在线设备失败")
				}
			}
			//从离线设备集合中移除
			_, offineOk := offlineDeviceList[device.Mac]
			if offineOk{
				OfflineJoinDeviceListCacheKey := constvar.RouterRedisPrefix + sn + storage.RedisJoinDeviceOfflineListKey
				_, delErr := storage.RedisZRem(OfflineJoinDeviceListCacheKey, device.Mac)
				if delErr != nil {
					e.Log("Info", "移除离线设备失败")
					return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "移除离线设备失败")
				}
			}
		}

		//添加离线设备
		for mac , _ := range onlineDeivceList{
			deviceUUID := e.Md5Str(sn+mac)
			deviceInfoCacheKey := constvar.RouterRedisPrefix + sn + storage.RedisJoinDeviceInfoKey + ":" + deviceUUID
			cacheData := map[string]interface{}{
				"offline": nowTimeUnix,
				"status":storage.JoinDevicesOffline,
				"dspeed":"0KB/s",
				"upspeed":"0KB/s",
			}
			_, setErr := storage.RedisHSet(deviceInfoCacheKey, cacheData, -1)
			if setErr != nil {
				e.Log("Info", "设备信息更新失败")
				return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "设备信息更新失败")
			}

			OfflineJoinDeviceListCacheKey := constvar.RouterRedisPrefix + sn + storage.RedisJoinDeviceOfflineListKey
			_, err := storage.RedisZAdd(OfflineJoinDeviceListCacheKey, mac, nowTimeUnix)
			if err != nil {
				e.Log("Info", "添加离线设备失败")
				return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "添加离线设备失败")
			}
			//从在线设备集合中移除
			OnlineJoinDeviceListCacheKey := constvar.RouterRedisPrefix + sn + storage.RedisJoinDeviceOnlineListKey
			_, delErr := storage.RedisZRem(OnlineJoinDeviceListCacheKey, mac)
			if delErr != nil {
				e.Log("Info", "移除在线设备失败")
				return ReturnErr(data.Mid, constvar.DownloadHeartResponeMtype, "移除在线设备失败")
			}
		}
	}

	return model.Response{
		Mid:    data.Mid,
		Mtype:  constvar.DownloadHeartResponeMtype,
		Info:   errInfo,
		Status: constvar.StatusOk,
	}
}

func (routerHeartHandle RouterHeartHandle) getPushData(sn string) (model.Response , error){
	//获取下载中任务队列
	tasks := []model.Task{}
	loadingTaskQueueCacheKey := constvar.RouterRedisPrefix + sn + storage.RedisRouterTaskLoadIngSetKey
	laodTaskNum, loadingErr := storage.RedisZCard(loadingTaskQueueCacheKey)
	if loadingErr != nil || laodTaskNum >= 1 {
		tasks = nil
	}
	res, _ := service.GetTaskQueueInfoCache(loadingTaskQueueCacheKey, sn, 10)
	for _, task := range res {
		//设置任务期望状态
		taskStatus, _ := strconv.Atoi(task["status"].(string))
		exceptStatus := model.DownLoadTaskLoading
		if taskStatus == model.TaskStatusPauseing {
			exceptStatus = model.DownLoadTaskPause
		}
		taskIdInt64, _ := strconv.ParseInt(task["taskId"].(string), 10, 64)
		loadTask := model.Task{
			URL:    task["url"].(string),
			TaskID: taskIdInt64,
			Status: exceptStatus,
		}
		if taskStatus != model.TaskStatusDeleting {
			tasks = append(tasks, loadTask)
		}
	}
	//获取最新任务版本号
	taskVer, getErr := service.UpdateTaskVerCache(sn)
	if getErr != nil {
		taskVer = 1
	}

	mid, getMidErr := service.GenMid(sn)
	if getMidErr != nil {
		return model.Response{}, getMidErr
	}
	var returnData interface{} = model.ResponseData{
		TasksVer: taskVer,
		Tasks:    tasks,
	}

	requestMsg := model.Response{
		Mid:   mid,
		Mtype: constvar.MtypePushTaskTodDownloadRequest,
		Time:  time.Now().Unix(),
		Data:  &returnData,
	}

	return requestMsg, nil
}

